﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Metadata.Edm;
using System.Data.Objects;
using System.Data;
using System.Linq.Expressions;
using System.Data.Objects.DataClasses;

namespace Httlgd.DataCenter.Services.Core
{
    public static class EFExtendMethod
    {
        /// <summary>
        /// Ensures that entity referenced by <paramref name="entityReference"/> is loaded.
        /// </summary>
        public static void EnsureLoad<TEntity>(this EntityReference<TEntity> entityReference) where TEntity : EntityObject
        {
            if (!entityReference.IsLoaded)
            {
                entityReference.Load();
            }
        }

        /// <summary>
        /// Ensures that entity collection is loaded.
        /// </summary>
        public static void EnsureLoad<TEntity>(this EntityCollection<TEntity> entityCollection) where TEntity : EntityObject
        {
            if (!entityCollection.IsLoaded)
            {
                entityCollection.Load();
            }
        }
        /// <summary>
        /// Check whether entity collection is empty
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="entityCollection"></param>
        /// <returns></returns>
        public static bool IsNullOrEmpty<TEntity>(this EntityCollection<TEntity> entityCollection) where TEntity : EntityObject
        {
            return (entityCollection == null || entityCollection.Count == 0);
        }

        //public static EntityType GetCSpaceEntityType<T>(this MetadataWorkspace workspace)
        //{
        //    if (workspace == null)
        //        throw new ArgumentNullException("workspace");
        //    // Make sure the assembly for "T" is loaded
        //    workspace.LoadFromAssembly(typeof(T).Assembly);
        //    // Try to get the ospace type and if that is found
        //    // look for the cspace type too.
        //    EntityType ospaceEntityType = null;
        //    StructuralType cspaceEntityType = null;
        //    if (workspace.TryGetItem<EntityType>(
        //        typeof(T).FullName,
        //        DataSpace.OSpace,
        //        out ospaceEntityType))
        //    {
        //        if (workspace.TryGetEdmSpaceType(
        //            ospaceEntityType,
        //            out cspaceEntityType))
        //        {
        //            return cspaceEntityType as EntityType;
        //        }
        //    }
        //    return null;
        //}

        //public static IEnumerable<EntityType> GetHierarchy(this EntityType entityType)
        //{
        //    if (entityType == null)
        //        throw new ArgumentNullException("entityType");
        //    while (entityType != null)
        //    {
        //        yield return entityType;
        //        entityType = entityType.BaseType as EntityType;
        //    }
        //}

        //public static IEnumerable<EntitySet> GetEntitySets(this MetadataWorkspace workspace, EntityType type)
        //{
        //    if (workspace == null)
        //        throw new ArgumentNullException("workspace");
        //    if (type == null)
        //        throw new ArgumentNullException("type");

        //    foreach (EntityType current in type.GetHierarchy())
        //    {
        //        foreach (EntityContainer container in
        //            workspace.GetItems<EntityContainer>(DataSpace.CSpace))
        //        {
        //            foreach (EntitySet set in
        //                container.BaseEntitySets.OfType<EntitySet>()
        //                .Where(e => e.ElementType == current))
        //            {
        //                yield return set;
        //            }
        //        }
        //    }
        //}
        //public static void AttachToDefaultSet<T>(this ObjectContext ctx, T entity)
        //{
        //    if (ctx == null) throw new ArgumentNullException("ctx");
        //    if (entity == null) throw new ArgumentNullException("entity");


        //    MetadataWorkspace wkspace = ctx.MetadataWorkspace;

        //    EntitySet set = wkspace
        //       .GetEntitySets(wkspace.GetCSpaceEntityType<T>())
        //       .Single();

        //    ctx.AttachTo(set.Name, entity);
        //}

        //public static IEnumerable<TEntity> Where<TEntity>(this ObjectStateManager manager, Func<TEntity, bool> predicate) where TEntity : class
        //{
        //    return manager.GetObjectStateEntries(
        //        EntityState.Added |
        //        EntityState.Deleted |
        //        EntityState.Modified |
        //        EntityState.Unchanged
        //    )
        //   .Where(entry => !entry.IsRelationship)
        //   .Select(entry => entry.Entity)
        //   .OfType<TEntity>()
        //   .Where(predicate);
        //}

        //public static TEntity GetOrCreateAndAttachStub<TEntity>(this ObjectQuery<TEntity> query, Expression<Func<TEntity, bool>> expression) where TEntity : class
        //{
        //    var context = query.Context;
        //    var osm = context.ObjectStateManager;
        //    TEntity entity = osm.Where(expression.Compile()).SingleOrDefault();

        //    if (entity == null)
        //    {
        //        entity = expression.Create();
        //        context.AttachToDefaultSet(entity);
        //    }
        //    return entity;
        //}

        //public static T Create<T>(this Expression<Func<T, bool>> predicateExpr)
        //{
        //    var initializerExpression = PredicateToConstructorVisitor.Convert<T>(predicateExpr);
        //    var initializerFunction = initializerExpression.Compile();
        //    return initializerFunction();
        //}


    }

    //public class PredicateToConstructorVisitor
    //{
    //    public static Expression<Func<T>> Convert<T>(Expression<Func<T, bool>> predicate)
    //    {
    //        PredicateToConstructorVisitor visitor = new PredicateToConstructorVisitor();
    //        return visitor.Visit<T>(predicate);
    //    }
    //    protected Expression<Func<T>> Visit<T>(Expression<Func<T, bool>> predicate)
    //    {
    //        return VisitLambda(predicate as LambdaExpression)
    //           as Expression<Func<T>>;
    //    }
    //    protected virtual Expression VisitLambda(LambdaExpression lambda)
    //    {
    //        if (lambda.Body is BinaryExpression)
    //        {
    //            // Create a new instance expression i.e.
    //            NewExpression newExpr = Expression.New(lambda.Parameters.Single().Type);

    //            BinaryExpression binary =
    //               lambda.Body as BinaryExpression;

    //            return Expression.Lambda(
    //                    Expression.MemberInit(
    //                        newExpr,
    //                        GetMemberAssignments(binary).ToArray()
    //                    )
    //                );
    //        }
    //        throw new InvalidOperationException(
    //            string.Format(
    //               "OnlyBinary Expressions are supported.\n\n{0}",
    //               lambda.Body.ToString()
    //            )
    //        );
    //    }

    //    protected IEnumerable<MemberAssignment> GetMemberAssignments(BinaryExpression binary)
    //    {
    //        if (binary.NodeType == ExpressionType.Equal)
    //        {
    //            yield return GetMemberAssignment(binary);
    //        }
    //        else if (binary.NodeType == ExpressionType.AndAlso)
    //        {
    //            foreach (var assignment in GetMemberAssignments(binary.Left as BinaryExpression).Concat(GetMemberAssignments(binary.Right as BinaryExpression)))
    //            {
    //                yield return assignment;
    //            }
    //        }
    //        else
    //            throw new NotSupportedException(binary.ToString());
    //    }

    //    protected MemberAssignment GetMemberAssignment(BinaryExpression binary)
    //    {
    //        if (binary.NodeType != ExpressionType.Equal)
    //            throw new InvalidOperationException(
    //               binary.ToString()
    //            );

    //        MemberExpression member = binary.Left as MemberExpression;

    //        ConstantExpression constant = GetConstantExpression(binary.Right);

    //        if (constant.Value == null)
    //            constant = Expression.Constant(null, member.Type);

    //        return Expression.Bind(member.Member, constant);
    //    }

    //    protected ConstantExpression GetConstantExpression(Expression expr)
    //    {
    //        if (expr.NodeType == ExpressionType.Constant)
    //        {
    //            return expr as ConstantExpression;
    //        }
    //        else
    //        {
    //            Type type = expr.Type;

    //            if (type.IsValueType)
    //            {
    //                expr = Expression.Convert(expr, typeof(object));
    //            }

    //            Expression<Func<object>> lambda = Expression.Lambda<Func<object>>(expr);

    //            Func<object> fn = lambda.Compile();

    //            return Expression.Constant(fn(), type);
    //        }
    //    }
    //}
}
